Skip to content

Cost model for multiIndexArray (CIP-0156) - #7869

Draft
Unisay wants to merge 4 commits into
masterfrom
yura/issue-2259-multi-index-array-costing
Draft

Cost model for multiIndexArray (CIP-0156)#7869
Unisay wants to merge 4 commits into
masterfrom
yura/issue-2259-multi-index-array-costing

Conversation

@Unisay

@Unisay Unisay commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Replaces the placeholder costing of multiIndexArray with a benchmarked model: CPU linear in the number of indices (linear_in_y), memory linear in the length of the result. The denotation forces each element read eagerly, as indexArray does, so the array access is paid for inside this builtin rather than wherever the element is later demanded. Resolves IntersectMBO/plutus-private#2259.

The number of indices is limited to 4096, because beyond that the execution time is not predictable from the index count alone. This is the same kind of limit, for the same kind of reason, as the ones on integerToByteString and replicateByte; see Note [Index count limitation for multiIndexArray]. It is far above any realistic use, since a 16384-byte transaction could not carry that many serialised indices even if it carried nothing else. It does need a CIP-0156 amendment, and it is much cheaper to add now than once the builtin is deployed.

Benchmarks cross log-spaced array sizes from 1 to 131072 with index counts from 1 to the limit, using uniformly random indices, plus off-grid points and two control cells with 1 KiB elements. Neither array size nor element size affects the cost. The index lists are deliberately given unfavourable spacing, described in Note [Scattered index lists], because a list built the obvious way gets favourable spacing and fitting to that would understate the cost. A few inputs, including the largest index count, are spaced as widely as a transaction's memory budget would allow, since the fit takes the slowest observation at each end of the range.

The slope and intercept come from a line through the ends of the benchmarked range rather than from least squares. Per-index time rises slightly with the index count, and least squares on such data returns a negative intercept, which adjustModel then clamps, discarding the fixed cost of a call along with it. The fit is checked against every data point, and as a sanity check on the outcome a single-index multiIndexArray is charged 311,081 ps against indexArray's 232,010, which is the right ordering because it does strictly more work.

parameter value
CPU intercept 268,678 ps
CPU slope 42,403 ps per index
memory 4 + 1 per index

ParamName entries for the four new parameters are appended to V1, V2 and V3, following the batch-6 precedent. A new page under doc/cost-models/multiindexarray plots the benchmark data against the model. Fitting the model locally requires working around the EqualsByteString off-diagonal data gap in models.R (see #7868).

@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.6.3

🚀 View preview at
https://IntersectMBO.github.io/plutus/pr-preview/cost-models/pr-7869/

Built to branch gh-pages at 2026-07-29 17:52 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@Unisay Unisay self-assigned this Jul 27, 2026
@Unisay
Unisay force-pushed the yura/issue-2259-multi-index-array-costing branch from 74cd44d to dcd569b Compare July 29, 2026 17:17
Unisay added 4 commits July 29, 2026 19:51
Adds the CPU and memory parameters for multiIndexArray to the model record, the JSON variants and the ledger API parameter lists.

The CPU model is fitted through the ends of the benchmarked range rather than by least squares. Per-index time rises across that range, and least squares then returns a negative intercept, which adjustModel clamps away together with the fixed cost of a call.
Beyond the limit the execution time is not predictable from the index count alone, so the cost model cannot bound it; this is the same kind of limit as the ones on integerToByteString and replicateByte. It is far above any realistic use, since a 16384-byte transaction could not carry that many serialised indices even if it carried nothing else.

The lookup moves into PlutusCore.Arrays, where the count is checked during the traversal rather than up front, since taking the length first would walk the list twice.
Index counts run from one to the limit, crossed with log-spaced array sizes, plus off-grid points and controls for element size. The index lists are given unfavourable spacing, so that the fit does not rest on the favourable spacing a straightforward generator produces; a few inputs, including the largest index count, are spaced as widely as a transaction's memory budget would allow, since those are the points the fit takes.

makeBenchmarks becomes IO, because fixing the layout requires building the lists into compact regions.
…used

The new page plots the benchmark data against the model plane and the per-index time distribution. All pages now read builtinCostModelE.json, the PlutusV3 model from PV 11 onwards, in place of C.
@Unisay
Unisay force-pushed the yura/issue-2259-multi-index-array-costing branch from dcd569b to 8cbcee0 Compare July 29, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant